///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef __HighLevelGpuProgramManager_H__
#define __HighLevelGpuProgramManager_H__

#include "OgrePrerequisites.h"
#include "OgreResourceManager.h"
#include "OgreSingleton.h"
#include "core/exception.h"
#include "OgreHighLevelGpuProgram.h"

namespace Ogre {

	class _OgreExport HighLevelGpuProgramFactory : public MemAlloc_General
	{
	public:
        HighLevelGpuProgramFactory() {}
        virtual ~HighLevelGpuProgramFactory();
		/// Get the name of the language this factory creates programs for
		virtual const String& getLanguage(void) const = 0;
        virtual HighLevelGpuProgram* create(ResourceManager* creator, 
            const String& name, ResourceHandle handle,
            const String& group, bool isManual, ManualResourceLoader* loader) = 0;
		virtual void destroy(HighLevelGpuProgram* prog) = 0;
	};
	
	class _OgreExport HighLevelGpuProgramManager 
		: public ResourceManager, public Singleton<HighLevelGpuProgramManager>
	{
	public:
		typedef map<String, HighLevelGpuProgramFactory*>::type FactoryMap;
	protected:
		/// Factories capable of creating HighLevelGpuProgram instances
		FactoryMap mFactories;

		/// Factory for dealing with programs for languages we can't create
		HighLevelGpuProgramFactory* mNullFactory;
		/// Factory for unified high-level programs
		HighLevelGpuProgramFactory* mUnifiedFactory;

		HighLevelGpuProgramFactory* getFactory(const String& language);

        /// @copydoc ResourceManager::createImpl
        Resource* createImpl(const String& name, ResourceHandle handle, 
            const String& group, bool isManual, ManualResourceLoader* loader,
            const NameValuePairList* params);
	public:
		HighLevelGpuProgramManager();
		~HighLevelGpuProgramManager();
		
		void addFactory(HighLevelGpuProgramFactory* factory);
		
		void removeFactory(HighLevelGpuProgramFactory* factory);
	
		bool isLanguageSupported(const String& lang);

		HighLevelGpuProgramPtr createProgram(
			const String& name, const String& groupName, 
            const String& language, GpuProgramType gptype);
    
        static HighLevelGpuProgramManager& getSingleton(void);
        
        static HighLevelGpuProgramManager* getSingletonPtr(void);

	};

}

#endif
